#include <REGX52.H>
#include <INTRINS.H>

sbit LCD1602_RS=P2^6;               // 数据/指令选择，1为数据，0为指令
sbit LCD1602_RW=P2^5;               // 读/写选择，1为读，0为写
sbit LCD1602_E=P2^7;                // 使能，1为数据有效，下降沿执行命令
#define LCD1602_DataPort    P0      // 数据输入/输出

/**
  * @brief @11.0592MHz，1ms
  * @param  无
  * @retval 无
  */
void LCD1602_Delay(void)
{
	unsigned char data i, j;

	_nop_();
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief 写入指令
  * @param  Command 指令
  * @retval 无
  */
void LCD1602_WriteCommand(unsigned char Command)
{
    LCD1602_RS=0;
    LCD1602_RW=0;
    LCD1602_DataPort=Command;
    LCD1602_E=1;
    LCD1602_Delay();
    LCD1602_E=0;
    LCD1602_Delay();
}

/**
  * @brief 写入数据
  * @param  Data 数据
  * @retval 无
  */
void LCD1602_WriteData(unsigned char Data)
{
    LCD1602_RS=1;
    LCD1602_RW=0;
    LCD1602_DataPort=Data;
    LCD1602_E=1;
    LCD1602_Delay();
    LCD1602_E=0;
    LCD1602_Delay();
}

/**
  * @brief 初始化
  * @param  无
  * @retval 无
  */
void LCD1602_Init(void)
{
    LCD1602_WriteCommand(0x38);     // 八位数据接口，两行显示，5*7点阵
	LCD1602_WriteCommand(0x0C);	    // 显示开，光标关，闪烁关
	LCD1602_WriteCommand(0x06); 	// 数据读写操作后，光标自动加一，画面不动
	LCD1602_WriteCommand(0x01); 	// 清屏
}

/**
  * @brief 设置光标位置
  * @param  Line    行数，1~2
  * @param  Column  列数，1~16
  * @retval 无
  */
void LCD1602_SetCursor(unsigned char Line,unsigned char Column)
{
    if(Line==1) LCD1602_WriteCommand(0x80|(Column-1));
    else LCD1602_WriteCommand(0x80|(Column-1)+0x40);
}

/**
  * @brief 显示字符
  * @param  Line    行数，1~2
  * @param  Column  列数，1~16
  * @param  Char    字符
  * @retval 无
  */
void LCD1602_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
{
    LCD1602_SetCursor(Line,Column);
    LCD1602_WriteData(Char);
}

/**
  * @brief 显示字符
  * @param  Line    行数，1~2
  * @param  Column  列数，1~16
  * @param  Str     字符串：在字符数组后加一个字符串结束标志，本质上是字符数组
  * @retval 无
  */
void LCD1602_ShowStr(unsigned char Line,unsigned char Column,unsigned char *Str)
{
    unsigned char i;
    LCD1602_SetCursor(Line,Column);
    // char z[]="ABC"; 等效于 char z[]={'A', 'B', 'C', '\0'};
    for(i=0;Str[i]!='\0';i++)
    {
        LCD1602_WriteData(Str[i]);
    }
}

/**
  * @brief  幂运算函数
  * @param  X   底数
  * @param  Y   指数
  * @retval Result  幂运算结果
  */
int LCD1602_Power(int X,int Y)
{
    unsigned char i;
    int Result=1;
    for(i=0;i<Y;i++)
    {
        Result*=X;
    }
    return Result;
}

/**
  * @brief 显示数字
  * @param  Line    行数，1~2
  * @param  Column  列数，1~16
  * @param  Num     数字，0~65535
  * @param  Length     长度，1~5
  * @retval 无
  */
void LCD1602_ShowNum(unsigned char Line,unsigned char Column,unsigned int Num,unsigned char Length)
{
    unsigned char i;
    LCD1602_SetCursor(Line,Column);
    // 思路就是将数字挨个拆分
    // 798/100%10=7;==>10^2==>Length-1
    // 798/10%10=9; ==>10^1==>Length-2
    // 798/1%10=8;  ==>10^0==>Length-3
    for(i=Length;i>0;i--)
    {
        // CGROM中字符码与字符字模关系对照表
        LCD1602_WriteData('0'+Num/LCD1602_Power(10,i-1)%10);
    }
}

/**
  * @brief 显示有符号数字
  * @param  Line    行数，1~2
  * @param  Column  列数，1~16
  * @param  Num     数字，-32768~32767
  * @param  Length  长度，1~5
  * @retval 无
  */
void LCD1602_ShowSignedNum(unsigned char Line,unsigned char Column,int Num,unsigned char Length)
{
    unsigned char i;
    LCD1602_SetCursor(Line,Column);
    
    // 正负部分
    if(Num>=0) 
    {
        LCD1602_WriteData('+');
    }
    else 
    {
        Num=-Num;
        LCD1602_WriteData('-');
    }
    
    // 数字部分
    for(i=Length;i>0;i--)
    {
        LCD1602_WriteData('0'+Num/LCD1602_Power(10,i-1)%10);
    }
}

/**
  * @brief 显示16进制数字
  * @param  Line    行数，1~2
  * @param  Column  列数，1~16
  * @param  Num     数字，0x0000~0xFFFF
  * @param  Length  长度，1~4
  * @retval 无
  */
void LCD1602_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Num,unsigned char Length)
{
    unsigned char i,n;
    LCD1602_SetCursor(Line,Column);

    for(i=Length;i>0;i--)
    {
        // 注意16进制计算方法
        n=Num/LCD1602_Power(16,i-1)%16;
        if(n<10) LCD1602_WriteData('0'+n);
        else LCD1602_WriteData('A'+n-10);
    }
}

/**
  * @brief 显示16进制数字
  * @param  Line    行数，1~2
  * @param  Column  列数，1~16
  * @param  Num     数字，0000 0000 0000 0000 ~ 1111 1111 1111 1111
  * @param  Length  长度，1~16
  * @retval 无
  */
void LCD1602_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Num,unsigned char Length)
{
    unsigned char i;
    LCD1602_SetCursor(Line,Column);

    for(i=Length;i>0;i--)
    {
        // 注意2进制计算方法
        LCD1602_WriteData('0'+Num/LCD1602_Power(2,i-1)%2);
    }
}